package demo;

import demo.certificate.CerLoad;
import demo.certificate.PKCS12LoadImp;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.api.UaClient;
import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfig;
import org.eclipse.milo.opcua.sdk.client.api.identity.UsernameProvider;
import org.eclipse.milo.opcua.stack.client.UaTcpStackClient;
import org.eclipse.milo.opcua.stack.core.types.builtin.*;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription;

import java.io.File;
import java.security.KeyPair;
import java.security.cert.X509Certificate;
import java.util.concurrent.ExecutionException;

import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint;

public class Demo2 {
    //定义OPC UA服务器的IP地址和端口
    private static String EndPointUrl = "opc.tcp://192.168.0.163:53530/OPCUA/SimulationServer";

    public static void main(String args[]) throws ExecutionException, InterruptedException {

        //定义证书文件路径
        //如果这个路径上没有这个证书 ，那么会新建一个，证书是用来连接opc-server的 ，证书的配置信息 不需要和 opc-server有关，
        //但是config里面的配置信息要和 opc-server 有关
        //如果是新建证书必须在OPC-SERVER 把这个证书trust一下
        //File cerfile = new File("E:\\slef-client2.pfx");
        File cerfile = new File("slef-client8.pfx");

        CerLoad cerLoad = new PKCS12LoadImp();    //加载pfx证书文件的实例
        //CerLoad cerLoad = new DerPemLoadImp();    加载der和pem证书文件的实例
        X509Certificate certificate  =cerLoad.getCer(cerfile);  //获取证书对象
        KeyPair keyPair = cerLoad.getKeyPair(cerfile);          //获取密钥对 对象

        //搜索OPC节点
        EndpointDescription[] endpointDescriptions = null;
        System.out.println("开始OPC连接...");
        try{
            endpointDescriptions = UaTcpStackClient.getEndpoints(EndPointUrl).get();
            System.out.println(endpointDescriptions[1]);
        }catch (Throwable e){
            System.out.println("获取端点失败");
            return;
        }

        /**
         * level -  mode
         *  1       sign
         *  0       None
         *  2       SignAndEncrypt
         *
         *  如果选择的是None 的EndpointDescription  那就不需要证书了。
         * */
        EndpointDescription endpointDescription = endpointDescriptions[0];


        //创建OpcUaClientConfig 配置对象
        // 下面的配置信息要和 opc-server 有关
        OpcUaClientConfig config = OpcUaClientConfig.builder()
                .setApplicationName(LocalizedText.english("SimulationServer"))
                //setApplicationUri 里面的ip 必须和 OPC-Server 所在的ip一致
                //（其实也不用和OPC-SERVER ip一致，，只要和生成证书的SelfSignedCertificateBuilder 里面的uri一致就行了）
                .setApplicationUri("urn:192.168.0.163:SimulationServer:client")
                .setCertificate(certificate)
                .setKeyPair(keyPair)
                .setEndpoint(endpointDescription)
                // 如果要 账号密码 验证 必须先在OPC-SERVER上添加 账号密码（如果有密码这里一定要加上）
                .setIdentityProvider(new UsernameProvider("CXCX","251128856"))
                .setRequestTimeout(uint(5000))
                .build();

        //利用OpcUaClientConfig创建OPC UA客户端

        OpcUaClient opcClient = new OpcUaClient(config);


        //先连接
        UaClient uaClient = opcClient.connect().get();


        //写入值
        int v = 70;
        float a = (float) 10.11;

        NodeId nodeId = new NodeId(3,"Int32");
        Variant value = new Variant(v);

        //test float   begin
        NodeId nodeId2 = new NodeId(3,"Float");
        Variant value2 = new Variant(a);
        DataValue dataValue2 = new DataValue(value2,null,null);
        StatusCode statusCode2 = uaClient.writeValue(nodeId2,dataValue2).get();
        //test float   end



        // 压力测试  开始
        while (true){
            DataValue dataValue = new DataValue(value,null,null);
            StatusCode statusCode = uaClient.writeValue(nodeId,dataValue).get();
            if(statusCode.isGood()){
                v++;
                value = new Variant(v);
                DataValue values = uaClient.readValue(0.0, TimestampsToReturn.Both,nodeId).get();
                System.out.println(values.getValue().getValue());
            }
        }
        // 压力测试  结束

        /*try {
            runner.Run(opcClient);
        }catch (Exception e){
            System.out.println("发生异常: "+e);
        }*/
    }
}